package com.example.demo.controller;

import com.alibaba.fastjson.JSON;
import com.example.demo.LogUtil;
import com.example.demo.Log_Exit_timeline;
import com.example.demo.repository.AutoMessageHandler;
import com.example.demo.service.SpyderInterfaceLight;
import com.normalClasses.eye.*;
import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

@Slf4j
@ServerEndpoint(value = "/ws/{userid}")
@Component
public class WebSocketController {
    @Autowired
    private SpyderInterfaceLight spyder;
    private Session session;
    private static Map<String, Session> sessionPool = new ConcurrentHashMap<>();
    private static Map<String, String> sessionIds = new ConcurrentHashMap<>();
    //管理时间保护措施用的池
    private static Map<String, Boolean> time_protect_pool = new ConcurrentHashMap<>();
    //消息管理队列,针对触动消息发送
    private static Queue_message_handler<socket_res_obj> request_message_handler = new Queue_message_handler();
    //针对定时任务的触发队列,公开成员，外部的类需要使用到
    public static Queue_message_handler<String> schedule_message_handler = new Queue_message_handler();
    //用于频繁点击行为检测
    private static Map<String, String> habit_protect_pool = new ConcurrentHashMap<>();

    @Autowired
    private Log_Exit_timeline timeline;

    @Autowired
    private AutoMessageHandler messageHandler;

    @Scheduled(fixedDelay = 50)
    public void request_handler() throws IOException {
        try {
            socket_res_obj now_handle_request = request_message_handler.pop();
            //System.out.println("zuse");
            String ans = spyder.socket_spyder(now_handle_request);
            JSONObject fin = (JSONObject) JSON.parse(ans);
            if (fin.getString("flag").equals("1")) {
                String jbox = fin.getString("jbox");
                String aans = fin.getString("ans");
                send_basic_Message(jbox, now_handle_request.getUserid());
                send_basic_Message(aans, now_handle_request.getUserid());
            } else if (fin.getString("flag").equals("2"))
                send_basic_Message(fin.getString("ans"), now_handle_request.getUserid());
            else {
                fin.remove("flag");
                send_basic_Message(fin.toString(), now_handle_request.getUserid());
            }
            //sendMessage("OK",now_handle_request.getUserid());
            if (now_handle_request.getMessage().getString("request_index").equals("2")) {
                spyder.storage_userhabit(now_handle_request);//异步执行，存储行为
                if (now_handle_request.getMessage().getString("event_id").equals("4")) {
                    JSONObject habit_json;
                    Date date = new Date();
                    SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");
                    String time_str = sf.format(date);
                    if (habit_protect_pool.get(now_handle_request.getUserid()) != null) {
                        String habit = habit_protect_pool.get(now_handle_request.getUserid());
                        habit_json = JSONObject.parseObject(habit);
                        String source_time = (String) habit_json.get("click_time_start");
                        Date d1 = (Date) sf.parse(source_time);
                        Date d2 = (Date) sf.parse(time_str);
                        int second = (int) (((d2.getTime() - d1.getTime()) / 1000));
                        if (second < 10) {
                            int click_times = (int) habit_json.get("click_times");
                            if (click_times >= 5) {
                                message message = new message();
                                message.setTitle("温馨提示");
                                message.setContent("您的点击次数过于频繁!");
                                send_basic_Message(JSON.toJSONString(message), now_handle_request.getUserid());
                                String info = "用户名为" + messageHandler.Auto_getusername(now_handle_request.getUserid()) + " 的用户点击过于频繁";
                                log.info(LogUtil.logSpec(info));
                            } else {
                                click_times += 1;
                                habit_json.remove("click_times");
                                habit_json.put("click_times", click_times);
                                habit_protect_pool.put(now_handle_request.getUserid(), habit_json.toString());
                            }
                        } else {
                            habit_protect_pool.remove(now_handle_request.getUserid());
                        }
                    } else {
                        JSONObject click = new JSONObject();
                        click.put("click_time_start", time_str);
                        click.put("click_times", 1);
                        habit_protect_pool.put(now_handle_request.getUserid(), click.toString());
                    }
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            log.error(LogUtil.logSpec("Queue_message_handler maybe has pop problem, or other reasons", 7));
        }

    }


    public static String[] getonlineUserid() {
        String[] userid = new String[getOnlineNum()];
        int i = 0;
        for (String key : sessionPool.keySet()) {
            userid[i] = key;
            i++;
        }
        return userid;
    }

    /**
     * @param userid 传入需要关闭的userid，其实就是用于连接时候的cookie凭证
     * @throws IOException
     */
    public static void close_session(String userid, String message) throws IOException {
        //发送消息给当前用户
        sendMessage(message, userid);
        //获得当前userid的session
        Session s = sessionPool.get(userid);
        //先将静态池子清空
        //sessionPool.remove(sessionIds.get(s.getId()));
        //sessionIds.remove(s.getId());
        //将会话销毁，主动关闭，会触动onclose的执行
        s.close();
    }

    /**
     * 用户连接时触发
     * *     *
     *
     * @param session session
     *                *@param userid  userid
     * @throws Exception
     */
    @OnOpen
    public void open(Session session, @PathParam(value = "userid") String userid) throws Exception {
        this.session = session;
        //每次新用户连接时，给固定任务的队列添加此用户
        this.schedule_message_handler.push(userid);
        String id = session.getId();
        Map<String, Object> userProperties = session.getUserProperties();
        System.out.println(userProperties);
        if (userProperties.size() > 0) {
            Set<Map.Entry<String, Object>> entries = userProperties.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                System.out.println(entry.getKey() + "----" + entry.getValue());
            }
        }
        System.out.println("id----->  " + id);
        sessionPool.put(userid, session);
        sessionIds.put(session.getId(), userid);
    }

    /**
     * 收到信息时触发     *     * @param message message
     *
     * @throws Exception
     */
    @OnMessage
    public void onMessage(String message) throws Exception {
        //log.info(LogUtil.logSpec("当前发送人sessionid为" + session.getId() + "发送内容为" + message,5);
        System.out.println("当前发送人sessionid为" + session.getId() + "发送内容为" + message);
        JSONObject rel_message = JSON.parseObject(message);
        socket_res_obj handle = new socket_res_obj(rel_message, sessionIds.get(session.getId()));
        this.request_message_handler.push(handle);
        //System.out.println(a.getInteger("hh")+"------------");
        //System.out.println(getOnlineNum());
        //this.session.getAsyncRemote().sendText(message);
        //this.onClose();
    }

    /**
     * 连接关闭触发
     */
    @OnClose
    public void onClose() {
        //防止前端ajax没有执行，加强的一道特殊保护
        String useridString = sessionIds.get(session.getId());
        time_protect_pool.put(useridString, true);
        sessionPool.remove(sessionIds.get(session.getId()));
        sessionIds.remove(session.getId());
        //移除行为
        if (habit_protect_pool.containsKey(useridString)) {
            habit_protect_pool.remove(useridString);
        }
        //System.out.println("对"+useridString+"保护措施得到执行");}
    }

    /**
     * 发生错误时触发     *     * @param session session     * @param error   error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void send_basic_Message(String message, String userId) throws IOException {
        Session s = sessionPool.get(userId);
        //Session s = redisUtil.get(userId);
        if (s != null) {
            s.getBasicRemote().sendText(message);
        }
    }

    /**
     * 信息发送的方法     *     * @param message message     * @param userId  userId
     */
    public static void sendMessage(String message, String userId) {
        Session s = sessionPool.get(userId);
        //Session s = redisUtil.get(userId);
        if (s != null) {
            s.getAsyncRemote().sendText(message);
        }
    }

    /**
     * 获取当前连接数     *     * @return int
     */
    public static int getOnlineNum() {
        return sessionPool.size();
    }

    /**
     * 获取在线用户名以---------隔开     *     * @return userId
     */
    public String getOnlineUsers() {
        StringBuilder users = new StringBuilder();
        for (String key : sessionIds.keySet()) {
            users.append(sessionIds.get(key)).append("---------");
        }
        return users.toString();
    }

    /**
     * 信息群发     *     * @param msg msg
     */
    public void sendAll(String msg) {
        for (String key : sessionIds.keySet()) {
            sendMessage(msg, sessionIds.get(key));
        }
    }

    /**
     * 多个人发送给指定的几个用户     *     * @param msg     msg     * @param persons 用户数组
     */
    public void sendMany(String msg, String[] persons) {
        for (String userid : persons) {
            sendMessage(msg, userid);
        }
    }

    @Scheduled(fixedDelay = 7500)
    public void scheduleTask() throws IOException {
        if (getOnlineNum() > 0) {
            for (String key : sessionIds.keySet()) {
                String message = messageHandler.Auto_output_message(sessionIds.get(key));
                //System.out.println(message);
                if (message != null) {
                    //发送一条优先级最高序号最低的消息
                    sendMessage(message, sessionIds.get(key));
                    //对已经读过的消息进行处理，避免重复发送
                    messageHandler.Auto_handle_readmessage(message, sessionIds.get(key));
                }
            }
            //System.out.println("定时执行了一次");
        }
        //当保护时间池增加了处理待处理事务，延时处理防止前端ajax接口未调用成功
        if (time_protect_pool.size() > 0) {
            for (String key : time_protect_pool.keySet()) {
                if (time_protect_pool.get(key)) {
                    long now_time = new Date().getTime();
                    if (!timeline.Updateexitime(key, String.valueOf(now_time)))
                        log.error(LogUtil.logSpec("7500 timed task error", 5));
                    time_protect_pool.remove(key);
                    log.info(LogUtil.logSpec("to " + key + " protection measures implemented", 5));

                }
            }
        }

    }
}